home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 52 / Amiga Format AFCD52 (Issue 136, May 2000).iso / -screenplay- / shareware / warpquake / warpquakesrc / d_sprite.c < prev    next >
C/C++ Source or Header  |  2000-02-29  |  11KB  |  443 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // d_sprite.c: software top-level rasterization driver module for drawing
  21. // sprites
  22.  
  23. #include "quakedef.h"
  24. #include "d_local.h"
  25.  
  26. static int        sprite_height;
  27. static int        minindex, maxindex;
  28. static sspan_t    *sprite_spans;
  29.  
  30. #if    !id386
  31.  
  32. /*
  33. =====================
  34. D_SpriteDrawSpans
  35. =====================
  36. */
  37. void D_SpriteDrawSpans (sspan_t *pspan)
  38. {
  39.     int            count, spancount, izistep;
  40.     int            izi;
  41.     byte        *pbase, *pdest;
  42.     fixed16_t    s, t, snext, tnext, sstep, tstep;
  43.     float        sdivz, tdivz, zi, z, du, dv, spancountminus1;
  44.     float        sdivz8stepu, tdivz8stepu, zi8stepu;
  45.     byte        btemp;
  46.     short        *pz;
  47.  
  48.     sstep = 0;    // keep compiler happy
  49.     tstep = 0;    // ditto
  50.  
  51.     pbase = cacheblock;
  52.  
  53.     sdivz8stepu = d_sdivzstepu * 8;
  54.     tdivz8stepu = d_tdivzstepu * 8;
  55.     zi8stepu = d_zistepu * 8;
  56.  
  57. // we count on FP exceptions being turned off to avoid range problems
  58.     izistep = (int)(d_zistepu * 0x8000 * 0x10000);
  59.  
  60.     do
  61.     {
  62.         pdest = (byte *)d_viewbuffer + (screenwidth * pspan->v) + pspan->u;
  63.         pz = d_pzbuffer + (d_zwidth * pspan->v) + pspan->u;
  64.  
  65.         count = pspan->count;
  66.  
  67.         if (count <= 0)
  68.             goto NextSpan;
  69.  
  70.     // calculate the initial s/z, t/z, 1/z, s, and t and clamp
  71.         du = (float)pspan->u;
  72.         dv = (float)pspan->v;
  73.  
  74.         sdivz = d_sdivzorigin + dv*d_sdivzstepv + du*d_sdivzstepu;
  75.         tdivz = d_tdivzorigin + dv*d_tdivzstepv + du*d_tdivzstepu;
  76.         zi = d_ziorigin + dv*d_zistepv + du*d_zistepu;
  77.         z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  78.     // we count on FP exceptions being turned off to avoid range problems
  79.         izi = (int)(zi * 0x8000 * 0x10000);
  80.  
  81.         s = (int)(sdivz * z) + sadjust;
  82.         if (s > bbextents)
  83.             s = bbextents;
  84.         else if (s < 0)
  85.             s = 0;
  86.  
  87.         t = (int)(tdivz * z) + tadjust;
  88.         if (t > bbextentt)
  89.             t = bbextentt;
  90.         else if (t < 0)
  91.             t = 0;
  92.  
  93.         do
  94.         {
  95.         // calculate s and t at the far end of the span
  96.             if (count >= 8)
  97.                 spancount = 8;
  98.             else
  99.                 spancount = count;
  100.  
  101.             count -= spancount;
  102.  
  103.             if (count)
  104.             {
  105.             // calculate s/z, t/z, zi->fixed s and t at far end of span,
  106.             // calculate s and t steps across span by shifting
  107.                 sdivz += sdivz8stepu;
  108.                 tdivz += tdivz8stepu;
  109.                 zi += zi8stepu;
  110.                 z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  111.  
  112.                 snext = (int)(sdivz * z) + sadjust;
  113.                 if (snext > bbextents)
  114.                     snext = bbextents;
  115.                 else if (snext < 8)
  116.                     snext = 8;    // prevent round-off error on <0 steps from
  117.                                 //  from causing overstepping & running off the
  118.                                 //  edge of the texture
  119.  
  120.                 tnext = (int)(tdivz * z) + tadjust;
  121.                 if (tnext > bbextentt)
  122.                     tnext = bbextentt;
  123.                 else if (tnext < 8)
  124.                     tnext = 8;    // guard against round-off error on <0 steps
  125.  
  126.                 sstep = (snext - s) >> 3;
  127.                 tstep = (tnext - t) >> 3;
  128.             }
  129.             else
  130.             {
  131.             // calculate s/z, t/z, zi->fixed s and t at last pixel in span (so
  132.             // can't step off polygon), clamp, calculate s and t steps across
  133.             // span by division, biasing steps low so we don't run off the
  134.             // texture
  135.                 spancountminus1 = (float)(spancount - 1);
  136.                 sdivz += d_sdivzstepu * spancountminus1;
  137.                 tdivz += d_tdivzstepu * spancountminus1;
  138.                 zi += d_zistepu * spancountminus1;
  139.                 z = (float)0x10000 / zi;    // prescale to 16.16 fixed-point
  140.                 snext = (int)(sdivz * z) + sadjust;
  141.                 if (snext > bbextents)
  142.                     snext = bbextents;
  143.                 else if (snext < 8)
  144.                     snext = 8;    // prevent round-off error on <0 steps from
  145.                                 //  from causing overstepping & running off the
  146.                                 //  edge of the texture
  147.  
  148.                 tnext = (int)(tdivz * z) + tadjust;
  149.                 if (tnext > bbextentt)
  150.                     tnext = bbextentt;
  151.                 else if (tnext < 8)
  152.                     tnext = 8;    // guard against round-off error on <0 steps
  153.  
  154.                 if (spancount > 1)
  155.                 {
  156.                     sstep = (snext - s) / (spancount - 1);
  157.                     tstep = (tnext - t) / (spancount - 1);
  158.                 }
  159.             }
  160.  
  161.             do
  162.             {
  163.                 btemp = *(pbase + (s >> 16) + (t >> 16) * cachewidth);
  164.                 if (btemp != 255)
  165.                 {
  166.                     if (*pz <= (izi >> 16))
  167.                     {
  168.                         *pz = izi >> 16;
  169.                         *pdest = btemp;
  170.                     }
  171.                 }
  172.  
  173.                 izi += izistep;
  174.                 pdest++;
  175.                 pz++;
  176.                 s += sstep;
  177.                 t += tstep;
  178.             } while (--spancount > 0);
  179.  
  180.             s = snext;
  181.             t = tnext;
  182.  
  183.         } while (count > 0);
  184.  
  185. NextSpan:
  186.         pspan++;
  187.  
  188.     } while (pspan->count != DS_SPAN_LIST_END);
  189. }
  190.  
  191. #endif
  192.  
  193.  
  194. /*
  195. =====================
  196. D_SpriteScanLeftEdge
  197. =====================
  198. */
  199. void D_SpriteScanLeftEdge (void)
  200. {
  201.     int            i, v, itop, ibottom, lmaxindex;
  202.     emitpoint_t    *pvert, *pnext;
  203.     sspan_t        *pspan;
  204.     float        du, dv, vtop, vbottom, slope;
  205.     fixed16_t    u, u_step;
  206.  
  207.     pspan = sprite_spans;
  208.     i = minindex;
  209.     if (i == 0)
  210.         i = r_spritedesc.nump;
  211.  
  212.     lmaxindex = maxindex;
  213.     if (lmaxindex == 0)
  214.         lmaxindex = r_spritedesc.nump;
  215.  
  216.     vtop = ceil (r_spritedesc.pverts[i].v);
  217.  
  218.     do
  219.     {
  220.         pvert = &r_spritedesc.pverts[i];
  221.         pnext = pvert - 1;
  222.  
  223.         vbottom = ceil (pnext->v);
  224.  
  225.         if (vtop < vbottom)
  226.         {
  227.             du = pnext->u - pvert->u;
  228.             dv = pnext->v - pvert->v;
  229.             slope = du / dv;
  230.             u_step = (int)(slope * 0x10000);
  231.         // adjust u to ceil the integer portion
  232.             u = (int)((pvert->u + (slope * (vtop - pvert->v))) * 0x10000) +
  233.                     (0x10000 - 1);
  234.             itop = (int)vtop;
  235.             ibottom = (int)vbottom;
  236.  
  237.             for (v=itop ; v<ibottom ; v++)
  238.             {
  239.                 pspan->u = u >> 16;
  240.                 pspan->v = v;
  241.                 u += u_step;
  242.                 pspan++;
  243.             }
  244.         }
  245.  
  246.         vtop = vbottom;
  247.  
  248.         i--;
  249.         if (i == 0)
  250.             i = r_spritedesc.nump;
  251.  
  252.     } while (i != lmaxindex);
  253. }
  254.  
  255.  
  256. /*
  257. =====================
  258. D_SpriteScanRightEdge
  259. =====================
  260. */
  261. void D_SpriteScanRightEdge (void)
  262. {
  263.     int            i, v, itop, ibottom;
  264.     emitpoint_t    *pvert, *pnext;
  265.     sspan_t        *pspan;
  266.     float        du, dv, vtop, vbottom, slope, uvert, unext, vvert, vnext;
  267.     fixed16_t    u, u_step;
  268.  
  269.     pspan = sprite_spans;
  270.     i = minindex;
  271.  
  272.     vvert = r_spritedesc.pverts[i].v;
  273.     if (vvert < r_refdef.fvrecty_adj)
  274.         vvert = r_refdef.fvrecty_adj;
  275.     if (vvert > r_refdef.fvrectbottom_adj)
  276.         vvert = r_refdef.fvrectbottom_adj;
  277.  
  278.     vtop = ceil (vvert);
  279.  
  280.     do
  281.     {
  282.         pvert = &r_spritedesc.pverts[i];
  283.         pnext = pvert + 1;
  284.  
  285.         vnext = pnext->v;
  286.         if (vnext < r_refdef.fvrecty_adj)
  287.             vnext = r_refdef.fvrecty_adj;
  288.         if (vnext > r_refdef.fvrectbottom_adj)
  289.             vnext = r_refdef.fvrectbottom_adj;
  290.  
  291.         vbottom = ceil (vnext);
  292.  
  293.         if (vtop < vbottom)
  294.         {
  295.             uvert = pvert->u;
  296.             if (uvert < r_refdef.fvrectx_adj)
  297.                 uvert = r_refdef.fvrectx_adj;
  298.             if (uvert > r_refdef.fvrectright_adj)
  299.                 uvert = r_refdef.fvrectright_adj;
  300.  
  301.             unext = pnext->u;
  302.             if (unext < r_refdef.fvrectx_adj)
  303.                 unext = r_refdef.fvrectx_adj;
  304.             if (unext > r_refdef.fvrectright_adj)
  305.                 unext = r_refdef.fvrectright_adj;
  306.  
  307.             du = unext - uvert;
  308.             dv = vnext - vvert;
  309.             slope = du / dv;
  310.             u_step = (int)(slope * 0x10000);
  311.         // adjust u to ceil the integer portion
  312.             u = (int)((uvert + (slope * (vtop - vvert))) * 0x10000) +
  313.                     (0x10000 - 1);
  314.             itop = (int)vtop;
  315.             ibottom = (int)vbottom;
  316.  
  317.             for (v=itop ; v<ibottom ; v++)
  318.             {
  319.                 pspan->count = (u >> 16) - pspan->u;
  320.                 u += u_step;
  321.                 pspan++;
  322.             }
  323.         }
  324.  
  325.         vtop = vbottom;
  326.         vvert = vnext;
  327.  
  328.         i++;
  329.         if (i == r_spritedesc.nump)
  330.             i = 0;
  331.  
  332.     } while (i != maxindex);
  333.  
  334.     pspan->count = DS_SPAN_LIST_END;    // mark the end of the span list 
  335. }
  336.  
  337.  
  338. /*
  339. =====================
  340. D_SpriteCalculateGradients
  341. =====================
  342. */
  343. void D_SpriteCalculateGradients (void)
  344. {
  345.     vec3_t        p_normal, p_saxis, p_taxis, p_temp1;
  346.     float        distinv;
  347.  
  348.     TransformVector (r_spritedesc.vpn, p_normal);
  349.     TransformVector (r_spritedesc.vright, p_saxis);
  350.     TransformVector (r_spritedesc.vup, p_taxis);
  351.     VectorInverse (p_taxis);
  352.  
  353.     distinv = 1.0 / (-DotProduct (modelorg, r_spritedesc.vpn));
  354.  
  355.     d_sdivzstepu = p_saxis[0] * xscaleinv;
  356.     d_tdivzstepu = p_taxis[0] * xscaleinv;
  357.  
  358.     d_sdivzstepv = -p_saxis[1] * yscaleinv;
  359.     d_tdivzstepv = -p_taxis[1] * yscaleinv;
  360.  
  361.     d_zistepu = p_normal[0] * xscaleinv * distinv;
  362.     d_zistepv = -p_normal[1] * yscaleinv * distinv;
  363.  
  364.     d_sdivzorigin = p_saxis[2] - xcenter * d_sdivzstepu -
  365.             ycenter * d_sdivzstepv;
  366.     d_tdivzorigin = p_taxis[2] - xcenter * d_tdivzstepu -
  367.             ycenter * d_tdivzstepv;
  368.     d_ziorigin = p_normal[2] * distinv - xcenter * d_zistepu -
  369.             ycenter * d_zistepv;
  370.  
  371.     TransformVector (modelorg, p_temp1);
  372.  
  373.     sadjust = ((fixed16_t)(DotProduct (p_temp1, p_saxis) * 0x10000 + 0.5)) -
  374.             (-(cachewidth >> 1) << 16);
  375.     tadjust = ((fixed16_t)(DotProduct (p_temp1, p_taxis) * 0x10000 + 0.5)) -
  376.             (-(sprite_height >> 1) << 16);
  377.  
  378. // -1 (-epsilon) so we never wander off the edge of the texture
  379.     bbextents = (cachewidth << 16) - 1;
  380.     bbextentt = (sprite_height << 16) - 1;
  381. }
  382.  
  383.  
  384. /*
  385. =====================
  386. D_DrawSprite
  387. =====================
  388. */
  389. void D_DrawSprite (void)
  390. {
  391.     int            i, nump;
  392.     float        ymin, ymax;
  393.     emitpoint_t    *pverts;
  394.     sspan_t        spans[MAXHEIGHT+1];
  395.  
  396.     sprite_spans = spans;
  397.  
  398. // find the top and bottom vertices, and make sure there's at least one scan to
  399. // draw
  400.     ymin = 999999.9;
  401.     ymax = -999999.9;
  402.     pverts = r_spritedesc.pverts;
  403.  
  404.     for (i=0 ; i<r_spritedesc.nump ; i++)
  405.     {
  406.         if (pverts->v < ymin)
  407.         {
  408.             ymin = pverts->v;
  409.             minindex = i;
  410.         }
  411.  
  412.         if (pverts->v > ymax)
  413.         {
  414.             ymax = pverts->v;
  415.             maxindex = i;
  416.         }
  417.  
  418.         pverts++;
  419.     }
  420.  
  421.     ymin = ceil (ymin);
  422.     ymax = ceil (ymax);
  423.  
  424.     if (ymin >= ymax)
  425.         return;        // doesn't cross any scans at all
  426.  
  427.     cachewidth = r_spritedesc.pspriteframe->width;
  428.     sprite_height = r_spritedesc.pspriteframe->height;
  429.     cacheblock = (byte *)&r_spritedesc.pspriteframe->pixels[0];
  430.  
  431. // copy the first vertex to the last vertex, so we don't have to deal with
  432. // wrapping
  433.     nump = r_spritedesc.nump;
  434.     pverts = r_spritedesc.pverts;
  435.     pverts[nump] = pverts[0];
  436.  
  437.     D_SpriteCalculateGradients ();
  438.     D_SpriteScanLeftEdge ();
  439.     D_SpriteScanRightEdge ();
  440.     D_SpriteDrawSpans (sprite_spans);
  441. }
  442.  
  443.